﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq.Expressions;

namespace CI.Models
{
    //TODO:Switch to release iMeta model base
    public class ModelBase : INotifyPropertyChanged
    {
        private bool _isRunning;

        public bool IsRunning
        {
            get { return _isRunning; }
            private set { SetField(ref _isRunning, value, () => IsRunning); }
        }

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

        #endregion

        protected void StartModel()
        {
            if (!IsRunning) IsRunning = true;
        }

        protected void StopModel()
        {
            if (IsRunning) IsRunning = false;
        }

        protected virtual void OnPropertyChanged(string propertyName)
        {
            
            VerifyPropertyName(propertyName);
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }

        [Conditional("DEBUG"), DebuggerStepThrough]
        private void VerifyPropertyName(string propertyName)
        {
            if (GetType().IsVisible)
            {
                if (!string.IsNullOrEmpty(propertyName) && GetType().GetProperty(propertyName) == null)
                    throw new ArgumentException("DependsOn name does not exists on target object.", "propertyName");
            }
        }

        protected bool SetField<T>(ref T field, T value, Expression<Func<T>> propertyExpression)
        {
            return SetField(ref field, value, propertyExpression, null);
        }

        protected bool SetField<T>(ref T field, T value, Expression<Func<T>> propertyExpression, Action changedMethod)
        {
            bool changed = !EqualityComparer<T>.Default.Equals(field, value);
            if (changed)
            {
                field = value;
                if (IsRunning)
                {
                    OnPropertyChanged(ExtractPropertyName(propertyExpression));
                    if (changedMethod != null) changedMethod.Invoke();
                }
            }
            return changed;
        }


        private static string ExtractPropertyName<T>(Expression<Func<T>> propertyExpression)
        {
            var memberExpression = propertyExpression.Body as MemberExpression;
            if (memberExpression == null)
                throw new ArgumentException("Expression must be a MemberExpression.", "propertyExpression");
            return memberExpression.Member.Name;
        }
    }
}